#include <QWidget>
#include "presenters_model_container.h"
#include "../models/model_container.h"
#include "../widgets/mesh_widget.h"
#include "../models/mesh_model.h"

using namespace mvp;

namespace presenters {

namespace {

  class Creator : public IPresenterCreator {
  public:
    virtual void Register(PresenterFactory *pFactory)
    {
      m_pFactory = pFactory;
    }
    
    virtual QObject * Attach(QObject *_pModel, QObject *_pView)
    {
      models::CContainer *pContainerModel = qobject_cast<models::CContainer *>(_pModel);
      
      if (pContainerModel == 0)
        return 0;
      
      QWidget *pWidget = qobject_cast<QWidget *>(_pView->parent());
      QString modelName = pWidget->windowTitle();
      QObject *pSubModel = pContainerModel->GetModel(modelName);

      if (pSubModel == 0)
      {
        modelName = "0";
        pSubModel = pContainerModel->GetModel(modelName);
      }
        
      if (pSubModel == 0)
        return 0;
        
      QObject *pSubPresenter = m_pFactory->Attach(pSubModel, _pView);
      
      if (pSubPresenter == 0)
        return 0;
        
      widgets::MeshWidget *pMeshWidget = qobject_cast<widgets::MeshWidget *>(_pView);
      
      CContainer *pPresenter = new CContainer(_pModel, modelName, pSubPresenter);
      
      if (pMeshWidget != 0)
      {
        QObject::connect(pMeshWidget, SIGNAL(OnElementPicked(IMesh::element_type, int)), pPresenter, SLOT(OnElementPicked(IMesh::element_type, int)));
      }
     
      return pPresenter;
    }
    
  private:
    PresenterFactory *m_pFactory;
  };
  
}

//
// presenters::CContainer
//

CContainer::CContainer(QObject *_pModel, const QString & _ModelName, QObject * _pSubPresenter)
{
  m_pModel = _pModel;
  m_ModelName = _ModelName;
  m_pSubPresenter = _pSubPresenter;
  m_pSubPresenter->setParent(this);
}


IPresenterCreator::SP CContainer::MakeCreator()
{
  return IPresenterCreator::SP(new Creator);
}

void CContainer::OnElementPicked(IMesh::element_type type, int index)
{
  if (m_ModelName == "2")
    return;
    
  if (m_ModelName == "0")
    Recalc("0", "1", index);
    
  if (m_ModelName == "1")
    Recalc("1", "2", index);
}

void CContainer::Recalc(const QString & l0, const QString & l1, int elementIndex)
{
  if (elementIndex < 0)
    return;
  using namespace models;
  
  models::CContainer *pContainer = (models::CContainer *) m_pModel;
  
  Mesh_model *pMesh0 = (Mesh_model *) pContainer->GetModel(l0);
  Mesh_model *pMesh1 = (Mesh_model *) pContainer->GetModel(l1);
  
  qreal sigma[3][3];
  
  {
    QVector<Mesh_model::Scalar_field::SP> Fields = pMesh0->get_frame()->get_element_field(IMesh::element_triangle);
    foreach (Mesh_model::Scalar_field::SP pField, Fields)
    {
      const qreal val = pField->get_values()[elementIndex * 3];

      if (pField->get_name() == "sigma_11")
        sigma[0][0] = val;
      if (pField->get_name() == "sigma_22")
        sigma[1][1] = val;
      if (pField->get_name() == "sigma_33")
        sigma[2][2] = val;
      if (pField->get_name() == "sigma_12")
        sigma[0][1] = sigma[1][0] = val;
      if (pField->get_name() == "sigma_13")
        sigma[0][2] = sigma[2][0] = val;
      if (pField->get_name() == "sigma_23")
        sigma[1][2] = sigma[2][1] = val;
    }
  }
  
  {
    QVector<Mesh_model::Scalar_field::SP> Fields = pMesh1->get_frame()->get_element_field(IMesh::element_triangle);
    const size_t size = Fields[0]->get_values().size(); 
    QVector<qreal> s11(size);
    QVector<qreal> s22(size);
    QVector<qreal> s33(size);
    QVector<qreal> s12(size);
    QVector<qreal> s13(size);
    QVector<qreal> s23(size);
    
    foreach (Mesh_model::Scalar_field::SP pField, Fields)
    {
      const QVector<qreal> & sct = pField->get_values();
      if (pField->get_name() == "sct_1111")
        for (int i = 0; i < size; ++i)
          s11[i] += sigma[0][0] * sct[i];
      if (pField->get_name() == "sct_1122")
        for (int i = 0; i < size; ++i)
          s11[i] += sigma[1][1] * sct[i];
      if (pField->get_name() == "sct_1133")
        for (int i = 0; i < size; ++i)
          s11[i] += sigma[2][2] * sct[i];
    }
    foreach (Mesh_model::Scalar_field::SP pField, Fields)
    {
      if (pField->get_name() == "sigma_11")
        pField->get_values() = s11;
      else
      if (pField->get_name() == "sigma_22")
        pField->get_values() = s22;
      else
      if (pField->get_name() == "sigma_33")
        pField->get_values() = s33;
      else
      if (pField->get_name() == "sigma_12")
        pField->get_values() = s12;
      else
      if (pField->get_name() == "sigma_13")
        pField->get_values() = s13;
      else
      if (pField->get_name() == "sigma_23")
        pField->get_values() = s23;
      else
        continue;

      pField->recalc();
    }
    pMesh1->set_current_frame(0);
  }
}

}